// 声明包(main包打包之后是一个可执行文件；其他包就是第三方包-工具类)
package main

import (
	"errors"
	"fmt"
	"strings"
)

// 依赖模块-切记双引号

// go fmt main.go保存时自动执行格式化
// 函数外只能放置标识符(变量、常量、函数、类型)的声明
// 程序入口：无参无返回值
func main() {
	s1 = "你a好#世a界"
	stuName = "aaa"
	// // GO语言中非全局变量声明后必须使用，苟泽编译不过去
	// fmt.Println("hello")      // 打印加换行
	// fmt.Printf("s1:%s\n", s1) // %s占位符-格式化打印
	// fmt.Print(s1)             // 终端输出不换行
	// fmt.Printf("%f\n", math.Pi)
	// fmt.Printf("%.2f\n", math.Pi)
	// f1 := 1.23456 // 默认定义的小数是float64类型
	// fmt.Printf("%T\n", f1)
	// f2 := float32(1.23456) // 显示声明float32类型
	// fmt.Printf("%T\n", f2)
	// fmt.Println)
	// fmt.Println(len(s1))
	// fmt.Println(s1+stuName, fmt.Sprintf("%s%s", s1, stuName))
	// ret := strings.Split(s1, "#")
	// fmt.Println(ret)
	// fmt.Println(strings.Contains(s1, "你好"))
	// fmt.Println(strings.HasPrefix(s1, "你好"), strings.HasSuffix(s1, "界"))
	// fmt.Println(strings.Index(s1, "a"), strings.LastIndex(s1, "a"))
	// fmt.Println(strings.Join(ret, "+"))
	traversalString()
}

// 遍历字符串
func traversalString() {
	// s := "hello世界세계"
	// for i := 0; i < len(s); i++ { //byte
	// 	fmt.Printf("%v(%c) ", s[i], s[i])
	// }
	// fmt.Println()
	// for a, r := range s { //rune
	// 	fmt.Printf("%v(%c：%c) ", r, r, a)
	// }
	// fmt.Println()
	// var a, b = 3, 4
	// var c int
	// // math.Sqrt()接收的参数是float64类型，需要强制转换
	// c = int(math.Sqrt(float64(a*a + b*b)))
	// fmt.Println(c)
	// s1 := "hello沙河小王子"
	// // ret := strings.Split(s1, "")
	// num := 0
	// for _, r := range s1 { //rune
	// 	if unicode.Is(unicode.Han, r) {
	// 		num++
	// 	}
	// }
	// fmt.Printf("%d", num)
	// 	var age = 9
	// 	if age >= 18 {
	// 		fmt.Println("成年")
	// 	} else if age < 8 {
	// 		fmt.Println("婴儿")
	// 	} else {
	// 		fmt.Println("小孩")
	// 	}

	// 	for i := 0; i < 10; i++ {
	// 		if i < 9 {
	// 			fmt.Printf("%d ", i)
	// 		} else {
	// 			fmt.Println(i)
	// 		}
	// 	}

	// 	var i = 0
	// 	for ; i < 10; i++ {
	// 		if i < 9 {
	// 			fmt.Printf("%d ", i)
	// 		} else {
	// 			fmt.Println(i)
	// 		}
	// 	}

	// 	var j = 0
	// 	for j < 10 {
	// 		if j < 9 {
	// 			fmt.Printf("%d ", j)
	// 		} else {
	// 			fmt.Println(j)
	// 		}
	// 		j++
	// 	}

	// 	// for {
	// 	// 	fmt.Println("无限循环")
	// 	// }

	// 	str := "你好世界！"
	// 	fmt.Println(len(str))
	// 	for i, v := range str {
	// 		// for _, v := range str {
	// 		fmt.Printf("%d %c\n", i, v)
	// 	}

	// for i := 1; i < 10; i++ {
	// 	for j := 1; j <= i; j++ {
	// 		fmt.Printf("%d * %d = %d\t", j, i, i*j)
	// 	}
	// 	fmt.Println()
	// }

	// for i := 9; i > 0; i-- {
	// 	for j := 1; j <= i; j++ {
	// 		fmt.Printf("%d * %d = %d\t", j, i, i*j)
	// 	}
	// 	fmt.Println()
	// }
	// score := 65
	// fmt.Println(score%2 == 1)

	// if score >= 90 {
	// 	fmt.Println("A")
	// } else if score > 75 {
	// 	fmt.Println("B")
	// } else {
	// 	fmt.Println("C")
	// }
	// if score := 65; score >= 90 {
	// 	fmt.Println("A")
	// } else if score > 75 {
	// 	fmt.Println("B")
	// } else {
	// 	fmt.Println("C")
	// }
	// n := 3
	// // even := n % 2
	// switch n {
	// // switch n := 7; n {// 1. 方案2：在 switch 表达式之前添加一个执行语句
	// case 1, 2, 3: // 2. 一个分支可以有多个值，多个case值中间使用英文逗号分隔。
	// 	fmt.Println("小于4")
	// 	fallthrough // 4. fallthrough语法可以执行满足条件的case的下一个case，是为了兼容C语言中的case设计的。
	// // case even > 0: // 3. 分支还可以使用表达式
	// // 	fmt.Println("偶数")
	// case 100:
	// 	fmt.Println("满分")
	// default:
	// 	fmt.Println("无效的输入！")
	// }
	// 	for i := 0; i < 10; i++ {
	// 		for j := 0; j < 10; j++ {
	// 			if j == 2 {
	// 				// 设置退出标签
	// 				goto breakTag
	// 			}
	// 			fmt.Printf("%v-%v\n", i, j)
	// 		}
	// 	}
	// 	// 标签
	// breakTag:
	// 	fmt.Println("结束for循环")
	// var (
	// 	a = 5
	// 	b = 2
	// 	c = true
	// )
	// fmt.Println(a + b)
	// fmt.Println(a - b)
	// fmt.Println(a * b)
	// fmt.Println(a / b)
	// fmt.Println(a % b)
	// a++
	// b--
	// fmt.Println(a, b)

	// fmt.Println(a == b)
	// fmt.Println(a != b)
	// fmt.Println(a >= b)
	// fmt.Println(a <= b)

	// if a > 18 && b < 60 {
	// 	fmt.Println("上班")
	// } else {
	// 	fmt.Println("paly")
	// }

	// if a < 18 || b > 60 {
	// 	fmt.Println("paly")
	// } else {
	// 	fmt.Println("上班")
	// }

	// fmt.Println(c, !c)
	// fmt.Println(5 & 2)   // 101 & 010 = 000
	// fmt.Println(5 | 2)   // 101 | 010 = 111
	// fmt.Println(5 ^ 2)   // 101 ^ 010 = 111
	// fmt.Println(5 << 10) // 101 <<  5120
	// fmt.Println(5 >> 10) // 101 >>  0

	// var (
	// 	a1 [3]string
	// 	a2 [3]string
	// )
	// fmt.Println(a1 == a2)
	// fmt.Println(a1)
	// fmt.Printf("a1:%T a2:%T\n", a1, a2)
	// var (
	// 	a1 = [...]int{1, 2, 3}
	// )
	// a2 := a1[:2]
	// fmt.Println(a1, a2)
	// a1[1] = 100
	// fmt.Println(a1, a2)
	// a3 := a2[1:2]
	// fmt.Println(a1, a3)
	// a4 := a1[:2:2]
	// fmt.Println(a1, a4)
	// a := [5]int{1, 2, 3, 4, 6}
	// a2 := a[1:2]
	// fmt.Printf("t:%v len(t):%v cap(t):%v\n", a2, len(a2), cap(a2))
	// a1 := a[1:2:5]
	// fmt.Printf("t:%v len(t):%v cap(t):%v\n", a1, len(a1), cap(a1))

	// var a = make([]string, 5, 10)
	// for i := 0; i < 10; i++ {
	// 	a = append(a, fmt.Sprintf("%v", i))
	// }
	// // fmt.Println(a, len(a))
	// var a = [...]int{3, 7, 8, 9, 1}
	// // b := sort.IntSlice{a...}
	// sort.Ints(a)
	// fmt.Println(a)
	// var m1 = make(map[string]int, 10)
	// m1["age"] = 111
	// // m2 := map[string]int{
	// // 	"year": 2020
	// // }
	// fmt.Println(m1)
	// scoreMap := make(map[string]int)
	// scoreMap["张三"] = 90
	// scoreMap["小明"] = 100
	// scoreMap["娜扎"] = 60
	// for _, v := range scoreMap {
	// 	fmt.Println(v)
	// }
	// rand.Seed(time.Now().UnixNano()) //初始化随机数种子
	// var scoreMap = make(map[string]int, 200)
	// for i := 0; i < 100; i++ {
	// 	key := fmt.Sprintf("stu%02d", i) //生成stu开头的字符串
	// 	value := rand.Intn(100)          //生成0~99的随机整数
	// 	scoreMap[key] = value
	// }
	// //取出map中的所有key存入切片keys
	// var keys = make([]string, 0, 200)
	// for key := range scoreMap {
	// 	keys = append(keys, key)
	// }
	// //对切片进行排序
	// sort.Strings(keys)
	// // fmt.Println(keys)
	// //按照排序后的key遍历map
	// for _, key := range keys {
	// 	fmt.Println(key, scoreMap[key])
	// }

	// var mapSlice = make([]map[string]string, 3)
	// for index, value := range mapSlice {
	// 	fmt.Printf("index:%d value:%v\n", index, value)
	// }
	// fmt.Println("after init")
	// // 对切片中的map元素进行初始化
	// mapSlice[0] = make(map[string]string, 10)
	// mapSlice[0]["name"] = "小王子"
	// mapSlice[0]["password"] = "123456"
	// mapSlice[0]["address"] = "沙河"
	// fmt.Println(mapSlice)
	// for index, value := range mapSlice {
	// 	fmt.Printf("index:%d value:%v\n", index, value)
	// }
	// var sliceMap = make(map[string][]string, 3)
	// fmt.Println(sliceMap)
	// fmt.Println("after init")
	// key := "中国"
	// value, ok := sliceMap[key]
	// if !ok {
	// 	value = make([]string, 0, 2)
	// }
	// value = append(value, "北京", "上海")
	// sliceMap[key] = value
	// fmt.Println(sliceMap)

	// type Map map[string][]int
	// m := make(Map)
	// s := []int{1, 2}
	// s = append(s, 3)
	// fmt.Printf("%+v\n", s)
	// m["q1mi"] = s
	// fmt.Printf("%v %+v\n", m, m["q1mi"])

	// s = append(s[:1], s[2:]...)
	// fmt.Printf("%+v\n", s)
	// fmt.Printf("%+v\n", m["q1mi"])

	// str := "how do you do"
	// s1 := strings.Split(str, " ") // 切割成切片类型
	// type Map map[string][]int
	// m := make(Map)
	// for i, v := range s1 {
	// 	_, ok := m[v]
	// 	if ok {
	// 		m[v] = append(m[v], i)
	// 	} else {
	// 		m[v] = append(make([]int, 0, 10), i)
	// 	}
	// }
	// for k, v := range m {
	// 	fmt.Println(k, len(v))
	// }
	// a := 10
	// b := &a                         // 取变量a的地址，将指针保存到b中
	// fmt.Printf("type of b:%T\n", b) // *int
	// c := *b                         // 指针取值（根据指针去内存取值）
	// fmt.Printf("type of c:%T\n", c) // int
	// fmt.Printf("value of c:%v\n", c)
	// var b map[string]int
	// b["沙河娜扎"] = 100
	// fmt.Println(b)
	// err := errors.New("无法识别的操作符")
	// fmt.Printf("%T", err)
	// fmt.Println("start")
	// defer fmt.Println(1)
	// defer fmt.Println(2)
	// fmt.Println("中间")
	// defer fmt.Println(3)
	// fmt.Println("end")
	// x := 1
	// y := 2
	// defer calc("AA", x/*1*/, calc("A", x, y)/*①A 1 2 3*/) //④AA 1 3 4
	// x = 10
	// defer calc("BB", x/*10*/, calc("B", x, y)/*②B 10 2 12*/)//③BB 10 12 22
	// y = 20
	// funcA()
	// funcB()
	// funcC()
	// var (
	// 	coins = 50
	// 	users = []string{
	// 		"Matthew", "Sarah", "Augustus", "Heidi", "Emilie", "Peter", "Giana",
	// 		"Adriano", "Aaron", "Elizabeth",
	// 	}
	// 	distribution = make(map[string]int, len(users))
	// )
	// newDistribution, left := dispatchCoin(distribution, users, coins)
	// fmt.Println(newDistribution)
	// fmt.Println("剩下：", left)
	// var (
	// 	name    string
	// 	age     int
	// 	married bool
	// )
	// // n, err := fmt.Scanln(&name, &age, &married)
	// n, err := fmt.Scanf("1:%s 2:%d 3:%t", &name, &age, &married)
	// fmt.Println(n, err)
	// fmt.Printf("扫描结果 name:%s age:%d married:%t \n", name, age, married)
	// s1 := fmt.Sprint("沙河小王子")
	// name := "沙河小王子"
	// age := 18
	// s2 := fmt.Sprintf("name:%s,age:%d", name, age)
	// s3 := fmt.Sprintln("沙河小王子")
	// fmt.Println(s1, s2, s3)
	// var (
	// 	name    string
	// 	age     int
	// 	married bool
	// )
	// fmt.Sscan("hao 23 true", &name, &age, &married)
	// fmt.Printf("扫描结果 name:%s age:%d married:%t \n", name, age, married)
	// reader := bufio.NewReader(os.Stdin) // 从标准输入生成读对象
	// fmt.Print("请输入内容：")
	// text, _ := reader.ReadString('\n') // 读到换行
	// text = strings.TrimSpace(text)
	// fmt.Printf("%#v\n", text)

	// 递归
	// i := 3
	// fmt.Printf("%d 的阶乘是 %d\n", i, recursion(3))
	// fmt.Println(taijie(3))

	// type student struct {
	// 	name string
	// 	age  int
	// }
	// m := make(map[string]*student)
	// stus := []student{
	// 	{name: "小王子", age: 18},
	// 	{name: "娜扎", age: 23},
	// 	{name: "大王八", age: 9000},
	// }
	// for _, stu := range stus {
	// 	fmt.Println(*&stu.name)
	// 	m[stu.name] = &stu
	// 	fmt.Println(*&stu.name)
	// }
	// for k, v := range m {
	// 	fmt.Println(k, "=>", v.name)
	// }

	p1 := newPerson1("hao", "wuhan", 23)
	fmt.Printf("%T %#v\n", p1, p1)
	p2 := newPerson2("hao", "wuhan", 23)
	fmt.Printf("%T %#v\n", p2, p2)
	p1.say()
	p2.say()
	// say()
}

func (p person) say() {
	fmt.Println("person的say方法", p)
}

type person struct {
	name string
	city string
	age  int
}

func newPerson1(name, city string, age int) person {
	return person{
		name: name,
		city: city,
		age:  age,
	}
}
func newPerson2(name, city string, age int) *person {
	return &person{
		name: name,
		city: city,
		age:  age,
	}
}
func recursion(n uint64) (result uint64) {
	// 3! = 3 * 2 * 1
	result = 1
	if n > 0 {
		result = n * recursion(n-1)
	}
	return
}

// n个台阶，可以一次走一步，一次走两步
func taijie(n uint64) (count uint64) {
	// 一个台阶有一种走法
	if n == 1 {
		return 1
	}
	// 2个台阶有2种走法
	if n == 2 {
		return 2
	}
	// n个递归
	return taijie(n-1) + taijie(n-2)
}

func dispatchCoin(distribution map[string]int, users []string, coins int) (map[string]int, int) {
	for _, v := range users {
		count := 0
		for _, s := range strings.Split(v, "") {
			if s == "e" || s == "E" {
				count++
			} else if s == "i" || s == "I" {
				count += 2

			} else if s == "o" || s == "O" {
				count += 3

			} else if s == "u" || s == "U" {
				count += 4
			}
		}
		distribution[v] = count
	}

	for _, n := range distribution {
		coins -= n
	}
	return distribution, coins
}

func funcA() {
	fmt.Println("func A")
}
func funcB() {
	defer func() {
		err := recover()
		//如果程序出出现了panic错误,可以通过recover恢复过来
		if err != nil {
			fmt.Println("recover in B")
		}
	}()
	panic("panic in B")
}
func funcC() {
	fmt.Println("func C")
}

func calc(index string, a, b int) int {
	ret := a + b
	fmt.Println(index, a, b, ret)
	return ret
}

func do(s string, add func(x, y int) int, sub func(x, y int) int) (func(int, int) int, error) {
	func() {
		fmt.Println("aa")
	}()
	switch s {
	case "+":
		return add, nil
	case "-":
		return sub, nil
	default:
		err := errors.New("无法识别的操作符")
		fmt.Printf("%T", err)
		return nil, err
	}
}
func fn1() int {
	return 100
}

// 返回值可以命名也可以不命名
// 命名的返回值就相当于在函数中事先声明了一个变量
// func fn2(x int, y int) (ret int) {
// 参数类型简写：当参数中连续两个及以上参数的一致时，可将非最后一个参数的类型简写
func fn2(x, y int) (ret int) {
	ret = x + y
	// return ret
	return // 使用命名返回值可以在return时省略
}

// 可变长参数：可传多个可不传，必须放在函数参数的最后
func fn4(s string, y ...int) int {
	fmt.Println(y) // y的类型的是切片[]int
	return 100
}

// 多个返回值
func fn3() (int, string) {
	return 1, "你好"
}

// Go语言中没有默认参数的概念，所见即所得

// 声明变量
var s1 string

// 推荐使用小驼峰
// var stu_name string
var stuName string = "www"
var stuAge = 10

// var StuName string
// 批量声明
var (
	name string
	age  int
	isOk bool
)
